﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Drawing.Imaging;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using DX.ViewModels;
using DX.Views;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Threading;
using Avalonia.Controls.ApplicationLifetimes;

namespace DX
{
    abstract class RouterFactory : IRouterFactory
    {
        protected RouterFactory(IServiceProvider serviceProvider, IClassicDesktopStyleApplicationLifetime applicationLifetime, MvvmOption options)
        {
            ApplicationLifetime = applicationLifetime;
            Option = options;
            this.ServiceProvider = serviceProvider.CreateScope().ServiceProvider;
            GetDefaultIcon();
        }

        public IClassicDesktopStyleApplicationLifetime ApplicationLifetime { get; }
        public MvvmOption Option { get; }

        public IServiceProvider ServiceProvider { get; }

        object icon = null;
        protected   void GetDefaultIcon()
        {
            icon=new object();
        }


        object IRouterFactory.GetView(Type viewModelType, string viewCode)
        {
            return CreateViewAndViewModel(viewModelType, viewCode);
        }
        protected bool ApplySettings(object target, IEnumerable<KeyValuePair<string, object>> settings)
        {
            if (settings != null)
            {
                var type = target.GetType();

                foreach (var pair in settings)
                {
                    var propertyInfo = type.GetProperty(pair.Key);

                    if (propertyInfo != null && propertyInfo.CanWrite)
                    {
                        propertyInfo.SetValue(target, pair.Value, null);
                    }
                }

                return true;
            }

            return false;
        }

        protected ViewForm CreateViewAndViewModel(Type viewModelType, string viewname = null)
        {
            IViewModel viewModel = CreateViewModel(viewModelType);

            IView view = CreateView(viewModelType, viewname);
            ViewForm form = Apply(viewModel, view) ?? throw new RouterException($"[{viewModelType.FullName}] 创建界面失败"); ;
            return form;
        }
        void IRouterFactory.ApplyGuardClose([NotNull] IViewModel viewModel, [NotNull] IView view)
        {
            if (view is ViewForm form) ApplyGuardClose(viewModel, form);
        }
        protected void ApplyGuardClose([NotNull] IViewModel viewModel, [NotNull] ViewForm form)
        {
            if (viewModel is IGuardClose guardClose)
            {
                bool actuallyClosing = false;
                EventHandler<WindowClosingEventArgs> Form_FormClosing = (sender, e) =>
                {
                    if (e.Cancel || actuallyClosing) return;
                    actuallyClosing = guardClose.GetActuallyClosing();
                    if (actuallyClosing) { return; }
                    e.Cancel = true;
                    guardClose.CanClose().ContinueWith(x =>
                    {
                        actuallyClosing = x.Result;
                        if (x.Result)
                        {

                            Dispatcher.UIThread.Post(() =>
                            {
                                form.Close();
                            });
                        }
                    });
                };
                form.Closing += Form_FormClosing;

            }
        }
        protected ViewForm Apply([NotNull] IViewModel viewModel, [NotNull] IView view)
        {

            ViewForm form = view as ViewForm;
            if (form != null)
            {
                form.DataContext = viewModel;
            }
            else if (view is ViewControl viewControl)
            {
                viewControl.DataContext = viewModel;
                form = new UserControlForm(viewControl);
            }
            else
            {
                return null;
            }

            if (view is IAttach attachView) attachView.Attach(view, viewModel);
            if (viewModel is IAttach attachViewModel) attachViewModel.Attach(view, viewModel);
            ApplyGuardClose(viewModel, form);

            return form;
        }



        protected IView CreateView(Type viewModelType, string viewname = null)
        {
            Type viewType = null;
            IView view = null;
            string tmpviewName = viewname;
            if (string.IsNullOrEmpty(tmpviewName))
            {
                tmpviewName = "default";
            }

            viewType = viewModelType.GetCustomAttributes<ViewTypeAttribute>(true).FirstOrDefault(n => string.Equals(n.ViewName, tmpviewName))?.ViewType;
            if (viewType == null)
            {
                throw new ViewNotFoundException($"[{viewModelType.FullName}] 没找到对应的界面的模板名称[{tmpviewName}]");
            }

            if (!typeof(IView).IsAssignableFrom(viewType))
            {
                throw new ViewNotFoundException($"[{viewModelType.FullName}]  对应的界面类[{viewType.FullName}]没有实现 IView 接口");
            }

            view = CreateInstanceT<IView>(viewType);
            return view;
        }
        T CreateInstanceT<T>(Type type)
        {
            var ins = ServiceProvider.GetService(type);
            if (ins is T t) return t;
            if (typeof(T).IsAssignableFrom(type))
                return (T)CreateInstance(type);
            return default(T);
        }
        [return: NotNull]
        object CreateInstance(Type type)
        {
            var instance = ServiceProvider.GetService(type);
            if (instance != null)
            {
                return instance;
            }
            if (type.IsArray) throw new RouterException("数组 不能通过动态创建");
            if (type == typeof(string)) throw new RouterException("字符串 不能通过动态创建");
            if (type.IsValueType) throw new RouterException(" 不能通过动态创建");
            var constructor = type.GetConstructors().FirstOrDefault();
            if (constructor == null)
            {
                throw new RouterException("因没有公开构造函数");
            }
            try
            {
                var args = constructor.GetParameters().Select(n => CreateInstance(n.ParameterType)).ToArray();
                return constructor.Invoke(args);
            }
            catch (Exception e)
            {

                throw new RouterException($"创建失败[{type.FullName}]", e);
            }

        }
        [return: NotNull]
        private IViewModel CreateViewModel(Type viewModelType)
        {
            ArgumentNullException.ThrowIfNull(viewModelType);
            if (!typeof(IViewModel).IsAssignableFrom(viewModelType))
            {
                throw new ViewNotFoundException($"[{viewModelType.FullName}]没有实现 IViewModel 接口");
            }
            IViewModel viewModel = CreateInstanceT<IViewModel>(viewModelType) ?? throw new ViewModelNotFoundException($"[{viewModelType.FullName}]创建失败");
            var context = ServiceProvider.GetRequiredService<ViewModelContext>();
            ApplySettings(viewModel, new Dictionary<string, object> { { "Context", context } });

            return viewModel;
        }



        object IRouterFactory.FindView(Type viewModelType)
        {
            return FindView(viewModelType);
        }
        [return: MaybeNull]
        protected Window FindView(Type viewModelType)
        {
            return ApplicationLifetime.Windows.FirstOrDefault(n => n.DataContext?.GetType() == viewModelType);

        }

    }
}
